package gpl.scotlandyard;

import gpl.scotlandyard.beans.adapters.SecuredFugitive;
import gpl.scotlandyard.beans.basics.Node;
import gpl.scotlandyard.beans.basics.Player;
import gpl.scotlandyard.services.basics.BoardManager;
import gpl.scotlandyard.services.basics.BoardManagerBuilder;
import gpl.scotlandyard.services.utils.MapLoader;
import gpl.scotlandyard.ui.GameFrame;
import gpl.scotlandyard.ui.dialogs.LocalStartDialog;
import gpl.scotlandyard.ui.tools.JDialogs;
import gpl.scotlandyard.utils.Config;
import gpl.scotlandyard.utils.Constants;
import gpl.scotlandyard.utils.I18n;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.prefs.InvalidPreferencesFormatException;

import javax.swing.UIManager;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

/**
 * Main entry point. It prepares logger, loads configuration, sets look and feel
 * and executes splash screen.
 * <p>
 * Log4J configuration file :
 * 
 * <pre>
 * LOG_FILE = &quot;configuration/log4j.properties&quot;
 * </pre>
 * 
 * <br>
 * Configuration file :
 * 
 * <pre>
 * CONF_FILE = &quot;configuration/scotlandyard.conf&quot;
 * </pre>
 * 
 * </p>
 * <p>
 * Provides error codes for system exit:
 * 
 * <pre>
 * STD_EXIT = 0
 * <br>
 * FATAL_CONFIG = 1
 * <br>
 * FATAL_I18N = 2
 * <br>
 * FATAL_IO = 3
 * </pre>
 * 
 * </p>
 * <p>
 * Provides version and environnement
 * </p>
 * 
 * @author Norbert Martin
 */
public class Main {

  private static final Logger LOG = Logger.getLogger(Main.class);

  /**
   * Application version on 3 digits for major and minor evolutions.
   */
  public static final String VERSION = "0.2.1";

  private static final String LOG4J_CONF_FILE = "configuration/log4j.properties";
  private static final String GAME_CONF_FILE = "configuration/scotlandyard_conf.xml";

  /**
   * Main entry point.
   * 
   * @param args
   *          are not used
   * @throws InterruptedException
   *           if occurred during splash screen
   */
  public static void main(String[] args) throws InterruptedException {
    init();

    try {

      String[] values = new String[] { I18n.get("LOCAL"), I18n.get("SERVER"), I18n.get("DISTANT") };
      String choice = (String) JDialogs.showInputChoices(null, "Game mode", values, values[0]);
      if (choice == null) {
        LOG.info("game cancelled");
        JDialogs.showInfo(null, I18n.get("BYE"));
        System.exit(Constants.STD_EXIT);
      }

      if (choice.equals(values[0])) {
        playLocalGame();
      } else if (choice.equals(values[1])) {
        LOG.warn("unsupported mode");
        JDialogs.showError(null, I18n.get("ERR_UNSUPPORT_MODE"));
        System.exit(Constants.STD_EXIT);
      } else if (choice.equals(values[2])) {
        LOG.warn("unsupported mode");
        JDialogs.showError(null, I18n.get("ERR_UNSUPPORT_MODE"));
        System.exit(Constants.STD_EXIT);
      } else {
        LOG.warn("unsupported mode");
        JDialogs.showError(null, I18n.get("ERR_UNSUPPORT_MODE"));
        System.exit(Constants.STD_EXIT);
      }
    } catch (IOException e) {
      LOG.fatal("Error while launching game : " + e.getLocalizedMessage());
      System.exit(Constants.FATAL_IO);
    }
  }

  /**
   * @throws IOException
   */
  private static void playLocalGame() throws IOException {
    LocalStartDialog start = new LocalStartDialog();
    start.setVisible(true);
    if (start.isCancelled()) {
      LOG.info("game cancelled");
      JDialogs.showInfo(null, I18n.get("BYE"));
      System.exit(Constants.STD_EXIT);
    }

    BoardManagerBuilder builder = new BoardManagerBuilder();
    for (String dname : start.getDetectiveNames()) {
      builder.addDetective(new Player(dname));
    }

    builder.addFugitive(new SecuredFugitive(start.getFugitiveName(), start.getFugitivePwd()));

    BufferedReader bufr = new BufferedReader(new FileReader(new File(Config.get("MAP_FILE"))));
    List<Node> map = MapLoader.loadMap(bufr);
    bufr = new BufferedReader(new FileReader(Config.get("LOC_FILE")));
    MapLoader.loadNodesLocation(bufr, map);
    builder.setMap(map);
    BoardManager boardManager = builder.getRandomBoardManager();
    new GameFrame(boardManager).setVisible(true);
    boardManager.startGame();
  }

  /**
   * Loads configuration file, look and feel and show splash screen.
   * 
   * @throws InterruptedException
   *           if occured during splash screen
   */
  private static void init() throws InterruptedException {
    // LOAD LOG4J CONF
    PropertyConfigurator.configure(LOG4J_CONF_FILE);
    LOG.info("Log4j configuration loaded : " + LOG4J_CONF_FILE);

    // LOAD CONFIGURATION
    try {
      File conf = new File(GAME_CONF_FILE);
      Config.load(conf);
      LOG.info("Game configuration loaded : " + conf.getAbsolutePath());
    } catch (IOException e) {
      String err = String.format(I18n.get("ERR_LOAD_CONFIG"), e.getLocalizedMessage());
      JDialogs.showError(null, err);
      LOG.fatal(err);
      System.exit(Constants.FATAL_CONFIG);
    } catch (InvalidPreferencesFormatException e) {
      String err = String.format(I18n.get("ERR_LOAD_CONFIG"), e.getLocalizedMessage());
      JDialogs.showError(null, err);
      LOG.fatal(err);
      System.exit(Constants.FATAL_CONFIG);
    }

    // SET SYSTEM LOOK AND FEEL
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      LOG.info("System look and feel set : " + UIManager.getLookAndFeel().getName());
    } catch (Exception e) {
      String err = String.format(I18n.get("ERR_UIMANAGER_LAF"), e.getLocalizedMessage());
      JDialogs.showError(null, err);
      LOG.error(err);
    }

    // SPLASH SLEEP
    LOG.info("splash screen sleep");
    Thread.sleep(Config.getInteger("SPLASH_TIME"));
  }

}
